package com.xjd.edu.toolkit.metrics.feign;

import feign.Client;
import feign.Request;
import feign.Response;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

/**
 * @author wangyu
 * @since 2023/2/8
 */
@Slf4j
public class FeignMeteredClient implements Client {

    private final Client delegate;
    private final MeterRegistry registry;

    public FeignMeteredClient(Client delegate, MeterRegistry registry) {
        this.delegate = delegate;
        this.registry = registry;
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        try {
            return this.timer(request).recordCallable(() -> delegate.execute(request, options));
        } catch (IOException e) {
            this.counter(request, e).increment();
            throw e;
        } catch (Exception e) {
            this.counter(request, e).increment();
            throw new IOException(e);
        }
    }

    private Timer timer(Request request) {
        return Timer.builder("feign.client")
                .tag("uri", request.requestTemplate().path())
                .register(registry);
    }

    private Counter counter(Request request, Exception e) {
        return Counter.builder("feign.client.error")
                .tag("uri", request.requestTemplate().path())
                .tag("exception", e.getClass().getName())   // 不同于Web过滤器中对异常的处理，Feign Client中异常是未经包装过的
                .register(registry);
    }

}
